/*
 * Copyright 2024 ywcai
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

`include "defines.v"
`timescale 1ns/1ps

module core(
	input	wire					clk,
	input	wire					rst_n,
	input	wire[`CacheBus]			mem_rd_data_i,
	input	wire					transact_done_i,
	input	wire[`IrqBus]			irq_i,

	output	wire					pp_en_o,
	output	wire					mem_req_o,
	output	wire					mem_we_o,
	output	wire[`MemAddrBus]		mem_addr_o,
	output	wire[`CacheBus]			mem_wr_data_o,
	output	wire[`CACHE_BITS/8-1:0]	mem_strb_o,
	output	wire[11:0]				mem_pulse_bits_o
	);

	wire				preif_req;
	wire[`MemAddrBus]	preif_pc;
	wire[`MemAddrBus]	if_pc;
	wire[`InstDataBus]	if_inst_i;
	wire[`InstDataBus]	if_inst_o;

	wire				reg_rs1_en;
	wire[`RegAddrBus]	reg_rs1_addr;
	wire[`RegDataBus]	reg_rs1_data;
	wire				reg_rs2_en;
	wire[`RegAddrBus]	reg_rs2_addr;
	wire[`RegDataBus]	reg_rs2_data;

	wire				icache_req_grant;
	wire				icache_inst_ready;
	wire[511:0]			icache_data_i;
	wire				icache_missing_req;
	wire[`MemAddrBus]	icache_missing_addr;
	wire[7:0]			icache_req_length;
	wire[7:0]			icache_req_offset;
	wire				icache_req_done;
	wire				dcache_req_i;
	wire				dcache_we_i;
	wire				dcache_we_o;
	wire[`MemAddrBus]	dcache_addr_i;
	wire[7:0]			dcache_strb_i;
	wire[7:0]			dcache_req_length;
	wire[7:0]			dcache_req_offset;
	wire[`RegDataBus]	dcache_data_mem_i;
	wire[511:0]			dcache_data_l2_i;
	wire[`RegDataBus]	dcache_rd_data_o;
	wire[`CacheBus]		dcache_wr_data_o;
	wire				dcache_mem_req;
	wire				dcache_req_grant_o;
	wire[`MemAddrBus]	dcache_missing_addr;
	wire				dcache_req_done;
	wire[511:0]			l2cache_rd_data;

	wire[`MemAddrBus]	id_pc_i;
	wire[`InstDataBus]	id_inst_i;
	wire				id_i_inst_auipc_i;
    wire[2:0]           id_mux_imm_src_i;
	wire[3:0]			id_mux_alu_ctrl_i;
    wire[3:0]           id_mux_mul_ctrl_i;
	wire[`MemAddrBus]	id_pc_o;
	wire[`InstDataBus]	id_inst_o;
    wire[6:0]			id_opcode_o;
    wire[2:0] 			id_funct3_o;
    wire[6:0] 			id_funct7_o;
	wire				id_regwrite_en_i;
	wire[`RegAddrBus]	id_regwrite_addr_o;
	wire    			id_mux_alu_src1_i;
	wire				id_mux_alu_src2_i;
	wire				id_mem_req_i;
	wire				id_mem_we_i;
	wire				id_mux_branch_i;
	wire[2:0]			id_mux_result_src_i;
	wire				id_mux_jump_i;
	wire				id_mux_pctarget_src_i;
	wire				id_mux_loadtype_i;
	wire				id_mux_storetype_i;
	wire[`RegDataBus]	id_rs1_imm_value_o;
	wire[`RegDataBus]	id_rs2_imm_value_o;
	wire				id_w_suffix_o;
	wire[`TrapBus]		id_trap_code_o;

	wire[`MemAddrBus]	ex_pc_i;
	wire[`InstDataBus]	ex_inst_i;
	wire				ex_i_inst_auipc_i;
	wire    			ex_mux_alu_src1_i;
	wire				ex_mux_alu_src2_i;
	wire[3:0]			ex_mux_alu_ctrl_i;
    wire[3:0]           ex_mux_mul_ctrl_i;
	wire				ex_mem_req_i;
	wire				ex_mem_we_i;
	wire				ex_mux_branch_i;
	wire[2:0]			ex_mux_result_src_i;
	wire				ex_mux_jump_i;
	wire				ex_mux_pctarget_src_i;
	wire				ex_mux_loadtype_i;
	wire				ex_mux_storetype_i;
	wire[`RegAddrBus]	ex_rs1_addr_i;
	wire[`RegDataBus]	ex_rs1_data_i;
	wire[`RegAddrBus]	ex_rs2_addr_i;
	wire[`RegDataBus]	ex_rs2_data_i;
	wire				ex_regwrite_en_i;
	wire[`RegAddrBus]	ex_regwrite_addr_i;
	wire[`RegDataBus]	ex_rs1_imm_value_i;
	wire[`RegDataBus]	ex_rs2_imm_value_i;
	wire[1:0]			ex_mux_forward_rs1_i;
	wire[1:0]			ex_mux_forward_rs2_i;
	wire				ex_w_suffix_i;
	wire[`TrapBus]		ex_trap_code_i;
	wire[`MemAddrBus]	ex_pc_o;
	wire[`InstDataBus]	ex_inst_o;
	wire				ex_i_inst_auipc_o;
	wire				ex_mem_req_o;
	wire				ex_mem_we_o;
	wire				ex_regwrite_en_o;
	wire[`RegAddrBus]   ex_regwrite_addr_o;
	wire[2:0]			ex_mux_result_src_o;
	wire				ex_mux_jump_o;
	wire				ex_mux_loadtype_o;
	wire				ex_mux_storetype_o;
	wire				ex_mux_pcsrc_o;
	wire[`RegDataBus]	ex_rs1_data_o;
	wire[`RegDataBus]	ex_rs2_data_o;
	wire[`RegDataBus]	ex_rs1_imm_value_o;
	wire[`RegDataBus]	ex_result_o;
	wire[`MemAddrBus]	ex_pc_target_o;
	wire[`TrapBus]		ex_trap_code_o;
    wire                div_stall_req_o;
	wire				ex_mem_req_stall_o;
    wire                ex_mem_inst_mulh_o;
    wire                ex_mem_inst_div_o;
    wire[`RegDataBus]   ex_mul_low_result_o;
    wire[`RegDataBus]   ex_div_rem_result_o;

	wire[`MemAddrBus]	mem_pc_i;
	wire[`InstDataBus]	mem_inst_i;
	wire				mem_i_inst_auipc;
	wire				mem_regwrite_en_i;
	wire[`RegAddrBus]	mem_regwrite_addr_i;
	wire				mem_mem_req_i;
	wire				mem_mem_we_i;
	wire[`RegDataBus]	mem_rs1_data_i;
	wire[`RegDataBus]	mem_rs2_data_i;
	wire[`RegDataBus]	mem_rs1_imm_value_i;
	wire[`RegDataBus]	mem_ex_result_i;
	wire[2:0]			mem_mux_result_src_i;
	wire				mem_mux_jump_i;
	wire				mem_mux_loadtype_i;
	wire				mem_mux_storetype_i;
	wire[`MemAddrBus]	mem_pc_target_i;
	wire[`TrapBus]		mem_trap_code_i;
	wire[`IrqBus]		mem_irq_i;
	wire[`MemAddrBus]	mem_pc_o;
	wire				mem_regwrite_en_o;
	wire[`RegAddrBus]	mem_regwrite_addr_o;
	wire[`RegDataBus]	mem_ex_result_o;
	wire[`MemAddrBus]	mem_pc_target_o;
	wire[2:0]			mem_mux_result_src_o;
	wire[`RegDataBus]	mem_read_data_o;
	wire[`TrapBus]		mem_trap_code_o;
	wire				mem_csr_wr_en_i;
	wire[`MemAddrBus]	mem_csr_wr_addr_i;
	wire[`RegDataBus]	mem_csr_wr_data_i;
	wire[`MemAddrBus]	mem_csr_rd_addr;
	wire[`RegDataBus]	mem_csr_rd_data_i;
	wire				mem_csr_wr_en_o;
	wire[`MemAddrBus]	mem_csr_wr_addr_o;
	wire[`RegDataBus]	mem_csr_wr_data_o;
	wire[`MemAddrBus]	mem_csr_rd_addr_o;
	wire[`RegDataBus]	mem_csr_rd_data_o;
	wire				mem_csr_mie_i;
	wire[`RegDataBus]	mem_csr_mtvec_i;
	wire[`RegDataBus]	mem_csr_mepc_i;
	wire[`RegDataBus]	mem_csr_mstatus_i;
	wire				mem_csr_mie_o;
	wire[`RegDataBus]	mem_csr_mtvec_o;
	wire[`RegDataBus]	mem_csr_mepc_o;
	wire[`RegDataBus]	mem_csr_mstatus_o;
	wire[`MemAddrBus]	mem_trap_entry_i;
    wire                mem_forward_inst_mulh;
    wire                mem_forward_inst_div;
    wire[`RegDataBus]   mem_forward_mul_low_result;
    wire[`RegDataBus]   mem_forward_div_rem_result;

	wire				wb_regwrite_en_o;
	wire[`RegAddrBus]	wb_regwrite_addr_o;
	wire[`RegDataBus]	wb_regwrite_data_o;

	wire[`MemAddrBus]	trap_pc_i;
	wire				trap_assert;
	wire				trap_flush_id_ex_req;

	wire				icache_load_stall_req;
	wire				dcache_load_stall_req;

	wire[`MemAddrBus]	ctrl_trap_entry_i;
	wire				ctrl_mux_pcsrc;
	wire[`MemAddrBus]	ctrl_pc_target;
	wire				stall_if_req;
	wire				stall_id_req;
    wire                stall_ex_req;
	wire				stall_mem_req;
	wire				flush_id_req;
	wire				flush_ex_req;
	wire				flush_mem_req;

	pc_reg i_pc_reg(
		.clk(clk),
		.rst_n(rst_n),
		.req_grant_i(icache_req_grant),
		.inst_ready_i(icache_inst_ready),
		.inst_i(if_inst_i),
		.stall_if_req_i(stall_if_req),
		.mux_pcsrc_i(ctrl_mux_pcsrc),
		.jump_target_i(ctrl_pc_target),
		.pp_en_o(pp_en_o),
		.mem_req_o(preif_req),
		.pc_o(if_pc),
		.next_pc_o(preif_pc),
		.inst_o(if_inst_o)
	);

	if_id i_if_id(
		.clk(clk),
		.rst_n(rst_n),
		.pc_i(if_pc),
		.inst_i(if_inst_o),
		.stall_id_req_i(stall_id_req),
		.flush_id_req_i(flush_id_req),
		.pc_o(id_pc_i),
		.inst_o(id_inst_i)
	);

	id i_id(
		.pc_i(id_pc_i),
		.inst_i(id_inst_i),
        .mux_imm_src_i(id_mux_imm_src_i),
		.pc_o(id_pc_o),
		.inst_o(id_inst_o),
		.opcode_o(id_opcode_o),
		.funct3_o(id_funct3_o),
		.funct7_o(id_funct7_o),
		.rs1_en_o(reg_rs1_en),
		.rs1_addr_o(reg_rs1_addr),
		.rs2_en_o(reg_rs2_en),
		.rs2_addr_o(reg_rs2_addr),
		.regwrite_addr_o(id_regwrite_addr_o),
		.rs1_imm_value_o(id_rs1_imm_value_o),
		.rs2_imm_value_o(id_rs2_imm_value_o),
		.trap_code_o(id_trap_code_o)
	);

	regfile i_regfile(
		.clk(clk),
		.rst_n(rst_n),
		.we_i(wb_regwrite_en_o),
		.waddr_i(wb_regwrite_addr_o),
		.wdata_i(wb_regwrite_data_o),
		.rs1_en_i(reg_rs1_en),
		.rs1_addr_i(reg_rs1_addr),
		.rs1_data_o(reg_rs1_data),
		.rs2_en_i(reg_rs2_en),
		.rs2_addr_i(reg_rs2_addr),
		.rs2_data_o(reg_rs2_data)
	);

	icache i_icache(
		.clk(clk),
		.rst_n(rst_n),
		.req_i(preif_req),
		.addr_i(preif_pc),
		.data_l2_i(icache_data_i),
		.req_done_i(icache_req_done),
		.addr_o(icache_missing_addr),
		.req_grant_o(icache_req_grant),
		.inst_o(if_inst_i),
		.inst_ready_o(icache_inst_ready),
		.missing_req_o(icache_missing_req),
		.bytes_req_o(icache_req_length),
		.bytes_offset_o(icache_req_offset),
		.i_load_stall_req_o(icache_load_stall_req)
	);

	dcache i_dcache(
		.clk(clk),
		.rst_n(rst_n),
        .req_i(dcache_req_i),
		.we_i(dcache_we_i),
		.addr_i(dcache_addr_i),
		.strb_i(dcache_strb_i),
		.wr_data_i(dcache_data_mem_i),
		.data_l2_i(dcache_data_l2_i),
		.req_done_i(dcache_req_done),
		.req_o(dcache_mem_req),
		.we_o(dcache_we_o),
		.addr_o(dcache_missing_addr),
		.data_o(dcache_rd_data_o),
		.cache_wr_o(dcache_wr_data_o),
		.req_grant_o(dcache_req_grant_o),
		.bytes_req_o(dcache_req_length),
		.bytes_offset_o(dcache_req_offset),
		.d_load_stall_req_o(dcache_load_stall_req)
	);

	l2cache i_l2cache(
		.clk(clk),
		.rst_n(rst_n),
		.i_missing_req_i(icache_missing_req),
		.i_addr_i(icache_missing_addr),
		.i_bytes_req_i(icache_req_length),
		.i_bytes_offset_i(icache_req_offset),
		.d_we_i(dcache_we_o),
		.d_addr_i(dcache_missing_addr),
		.d_bytes_req_i(dcache_req_length),
		.d_bytes_offset_i(dcache_req_offset),
		.d_cache_wr_i(dcache_wr_data_o),
		.d_mem_req_i(dcache_mem_req),
		.transact_done_i(transact_done_i),
		.rd_data_i(mem_rd_data_i),
		.i_data_l2_o(icache_data_i),
		.i_req_done_o(icache_req_done),
		.d_data_l2_o(dcache_data_l2_i),
		.d_req_done_o(dcache_req_done),
		.we_o(mem_we_o),
		.addr_o(mem_addr_o),
		.wr_data_o(mem_wr_data_o),
		.wr_strb_o(mem_strb_o),
		.pulse_bits_o(mem_pulse_bits_o),
		.mem_req_o(mem_req_o)
	);

	id_ex i_id_ex(
		.clk(clk),
		.rst_n(rst_n),
		.pc_i(id_pc_o),
		.inst_i(id_inst_o),
		.i_inst_auipc_i(id_i_inst_auipc_i),
        .stall_ex_req_i(stall_ex_req),
		.flush_ex_req_i(flush_ex_req),
		.mux_alu_src1_i(id_mux_alu_src1_i),
		.mux_alu_src2_i(id_mux_alu_src2_i),
		.mux_alu_ctrl_i(id_mux_alu_ctrl_i),
        .mux_mul_ctrl_i(id_mux_mul_ctrl_i),
		.mem_req_i(id_mem_req_i),
		.mem_we_i(id_mem_we_i),
		.mux_branch_i(id_mux_branch_i),
		.mux_result_src_i(id_mux_result_src_i),
		.mux_jump_i(id_mux_jump_i),
		.mux_pctarget_src_i(id_mux_pctarget_src_i),
		.mux_loadtype_i(id_mux_loadtype_i),
		.mux_storetype_i(id_mux_storetype_i),
		.rs1_addr_i(reg_rs1_addr),
		.rs1_data_i(reg_rs1_data),
		.rs2_addr_i(reg_rs2_addr),
		.rs2_data_i(reg_rs2_data),
		.regwrite_en_i(id_regwrite_en_i),
		.regwrite_addr_i(id_regwrite_addr_o),
		.rs1_imm_value_i(id_rs1_imm_value_o),
		.rs2_imm_value_i(id_rs2_imm_value_o),
		.w_suffix_i(id_w_suffix_o),
		.trap_code_i(id_trap_code_o),
		.pc_o(ex_pc_i),
		.inst_o(ex_inst_i),
		.i_inst_auipc_o(ex_i_inst_auipc_i),
		.mux_alu_src1_o(ex_mux_alu_src1_i),
		.mux_alu_src2_o(ex_mux_alu_src2_i),
		.mux_alu_ctrl_o(ex_mux_alu_ctrl_i),
        .mux_mul_ctrl_o(ex_mux_mul_ctrl_i),
		.mem_req_o(ex_mem_req_i),
		.mem_we_o(ex_mem_we_i),
		.mux_branch_o(ex_mux_branch_i),
		.mux_result_src_o(ex_mux_result_src_i),
		.mux_jump_o(ex_mux_jump_i),
		.mux_pctarget_src_o(ex_mux_pctarget_src_i),
		.mux_loadtype_o(ex_mux_loadtype_i),
		.mux_storetype_o(ex_mux_storetype_i),
		.rs1_addr_o(ex_rs1_addr_i),
		.rs1_data_o(ex_rs1_data_i),
		.rs2_addr_o(ex_rs2_addr_i),
		.rs2_data_o(ex_rs2_data_i),
		.regwrite_en_o(ex_regwrite_en_i),
		.regwrite_addr_o(ex_regwrite_addr_i),
		.rs1_imm_value_o(ex_rs1_imm_value_i),
		.rs2_imm_value_o(ex_rs2_imm_value_i),
		.w_suffix_o(ex_w_suffix_i),
		.trap_code_o(ex_trap_code_i)
		);

	ex i_ex(
        .clk(clk),
        .rst_n(rst_n),
        .stall_ex_req_i(stall_ex_req),
		.stall_mem_req_i(stall_mem_req),
		.pc_i(ex_pc_i),
		.inst_i(ex_inst_i),
		.i_inst_auipc_i(ex_i_inst_auipc_i),
		.mux_alu_src1_i(ex_mux_alu_src1_i),
		.mux_alu_src2_i(ex_mux_alu_src2_i),
		.mux_alu_ctrl_i(ex_mux_alu_ctrl_i),
        .mux_mul_ctrl_i(ex_mux_mul_ctrl_i),
		.mem_req_i(ex_mem_req_i),
		.mem_we_i(ex_mem_we_i),
		.mux_branch_i(ex_mux_branch_i),
		.mux_result_src_i(ex_mux_result_src_i),
		.mux_jump_i(ex_mux_jump_i),
		.mux_pctarget_src_i(ex_mux_pctarget_src_i),
		.mux_loadtype_i(ex_mux_loadtype_i),
		.mux_storetype_i(ex_mux_storetype_i),
		.rs1_addr_i(ex_rs1_addr_i),
		.rs1_data_i(ex_rs1_data_i),
		.rs2_addr_i(ex_rs2_addr_i),
		.rs2_data_i(ex_rs2_data_i),
		.regwrite_en_i(ex_regwrite_en_i),
		.regwrite_addr_i(ex_regwrite_addr_i),
		.rs1_imm_value_i(ex_rs1_imm_value_i),
		.rs2_imm_value_i(ex_rs2_imm_value_i),
		.mux_forward_rs1_i(ex_mux_forward_rs1_i),
		.mux_forward_rs2_i(ex_mux_forward_rs2_i),
		.w_suffix_i(ex_w_suffix_i),
		.wb_regwrite_data_i(wb_regwrite_data_o),
		.mem_forward_result_i(mem_ex_result_i),
		.mem_forward_pctarget_i(mem_pc_target_i),
		.trap_code_i(ex_trap_code_i),
        .mem_regwrite_addr_i(mem_regwrite_addr_i),
        .mem_inst_mulh_i(mem_forward_inst_mulh),
        .mem_inst_div_i(mem_forward_inst_div),
        .mul_low_result_i(mem_forward_mul_low_result),
        .div_rem_result_i(mem_forward_div_rem_result),
        .req_grant_i(dcache_req_grant_o),
		.pc_o(ex_pc_o),
		.inst_o(ex_inst_o),
		.i_inst_auipc_o(ex_i_inst_auipc_o),
		.regwrite_en_o(ex_regwrite_en_o),
		.regwrite_addr_o(ex_regwrite_addr_o),
		.mem_req_o(dcache_req_i),
		.mem_we_o(dcache_we_i),
		.mem_addr_o(dcache_addr_i),
		.mem_strb_o(dcache_strb_i),
		.mem_wr_data_o(dcache_data_mem_i),
		.rs1_data_o(ex_rs1_data_o),
		.rs2_data_o(ex_rs2_data_o),
		.rs1_imm_value_o(ex_rs1_imm_value_o),
		.ex_result_o(ex_result_o),
		.mux_result_src_o(ex_mux_result_src_o),
		.mux_pcsrc_o(ex_mux_pcsrc_o),
		.pc_target_o(ex_pc_target_o),
		.trap_code_o(ex_trap_code_o),
        .mem_inst_mulh_o(ex_mem_inst_mulh_o),
        .mem_inst_div_o(ex_mem_inst_div_o),
        .mul_low_result_o(ex_mul_low_result_o),
        .div_rem_result_o(ex_div_rem_result_o),
        .div_stall_req_o(div_stall_req_o),
		.mem_req_stall_o(ex_mem_req_stall_o)
	);

	ex_mem i_ex_mem(
		.clk(clk),
		.rst_n(rst_n),
		.pc_i(ex_pc_o),
		.inst_i(ex_inst_o),
		.i_inst_auipc_i(ex_i_inst_auipc_o),
		.regwrite_en_i(ex_regwrite_en_o),
		.regwrite_addr_i(ex_regwrite_addr_o),
		.rs1_data_i(ex_rs1_data_o),
		.rs2_data_i(ex_rs2_data_o),
		.rs1_imm_value_i(ex_rs1_imm_value_o),
		.ex_result_i(ex_result_o),
		.mux_result_src_i(ex_mux_result_src_o),
		.mux_jump_i(ex_mux_jump_o),
		.mux_loadtype_i(ex_mux_loadtype_o),
		.mux_storetype_i(ex_mux_storetype_o),
		.pc_target_i(ex_pc_target_o),
		.trap_code_i(ex_trap_code_o),
        .mem_inst_mulh_i(ex_mem_inst_mulh_o),
        .mem_inst_div_i(ex_mem_inst_div_o),
        .mul_low_result_i(ex_mul_low_result_o),
        .div_rem_result_i(ex_div_rem_result_o),
		.stall_mem_req_i(stall_mem_req),
		.flush_mem_req_i(flush_mem_req),
		.pc_o(mem_pc_i),
		.inst_o(mem_inst_i),
		.i_inst_auipc_o(mem_i_inst_auipc),
		.regwrite_en_o(mem_regwrite_en_i),
		.regwrite_addr_o(mem_regwrite_addr_i),
		.rs1_data_o(mem_rs1_data_i),
		.rs2_data_o(mem_rs2_data_i),
		.rs1_imm_value_o(mem_rs1_imm_value_i),
		.ex_result_o(mem_ex_result_i),
		.mux_result_src_o(mem_mux_result_src_i),
		.mux_jump_o(mem_mux_jump_i),
		.mux_loadtype_o(mem_mux_loadtype_i),
		.mux_storetype_o(mem_mux_storetype_i),
		.pc_target_o(mem_pc_target_i),
		.trap_code_o(mem_trap_code_i),
        .mem_inst_mulh_o(mem_forward_inst_mulh),
        .mem_inst_div_o(mem_forward_inst_div),
        .mul_low_result_o(mem_forward_mul_low_result),
        .div_rem_result_o(mem_forward_div_rem_result)
	);

	mem i_mem(
		.inst_i(mem_inst_i),
		.pc_i(mem_pc_i),
		.regwrite_en_i(mem_regwrite_en_i),
		.regwrite_addr_i(mem_regwrite_addr_i),
		.mem_read_data_i(dcache_rd_data_o),
		.rs1_data_i(mem_rs1_data_i),
		.rs2_data_i(mem_rs2_data_i),
		.rs1_imm_value_i(mem_rs1_imm_value_i),
		.ex_result_i(mem_ex_result_i),
		.mux_result_src_i(mem_mux_result_src_i),
		.mux_jump_i(mem_mux_jump_i),
		.mux_loadtype_i(mem_mux_loadtype_i),
		.mux_storetype_i(mem_mux_storetype_i),
		.pc_target_i(mem_pc_target_i),
		.csr_mie_i(mem_csr_mie_i),
		.csr_rd_data_i(mem_csr_rd_data_i),
		.csr_wr_en_i(mem_csr_wr_en_i),
		.csr_wr_addr_i(mem_csr_wr_addr_i),
		.csr_wr_data_i(mem_csr_wr_data_i),
		.csr_mtvec_i(mem_csr_mtvec_i),
		.csr_mepc_i(mem_csr_mepc_i),
		.csr_mstatus_i(mem_csr_mstatus_i),
		.irq_i(mem_irq_i),
		.trap_code_i(mem_trap_code_i),
		.trap_assert_i(trap_assert),
		.trap_entry_i(mem_trap_entry_i),
		.pc_o(mem_pc_o),
		.trap_pc_o(trap_pc_i),
		.regwrite_en_o(mem_regwrite_en_o),
		.regwrite_addr_o(mem_regwrite_addr_o),
		.ex_result_o(mem_ex_result_o),
		.pc_target_o(mem_pc_target_o),
		.mux_result_src_o(mem_mux_result_src_o),
		.mem_read_data_o(mem_read_data_o),
		.csr_mie_o(mem_csr_mie_o),
		.csr_wr_en_o(mem_csr_wr_en_o),
		.csr_wr_addr_o(mem_csr_wr_addr_o),
		.csr_wr_data_o(mem_csr_wr_data_o),
		.csr_rd_addr_o(mem_csr_rd_addr_o),
		.csr_rd_data_o(mem_csr_rd_data_o),
		.csr_mtvec_o(mem_csr_mtvec_o),
		.csr_mepc_o(mem_csr_mepc_o),
		.csr_mstatus_o(mem_csr_mstatus_o),
		.trap_code_o(mem_trap_code_o),
		.trap_entry_o(ctrl_trap_entry_i)
	);

	mem_wb i_wb(
		.clk(clk),
		.rst_n(rst_n),
		.pc_i(mem_pc_o),
		.regwrite_en_i(mem_regwrite_en_o),
		.regwrite_addr_i(mem_regwrite_addr_o),
		.mem_read_data_i(mem_read_data_o),
		.ex_result_i(mem_ex_result_o),
		.pc_target_i(mem_pc_target_o),
		.csr_rd_data_i(mem_csr_rd_data_o),
		.mux_result_src_i(mem_mux_result_src_o),
		.regwrite_en_o(wb_regwrite_en_o),
		.regwrite_addr_o(wb_regwrite_addr_o),
		.regwrite_data_o(wb_regwrite_data_o)
	);

	ctrl i_ctrl(
		.id_opcode_i(id_opcode_o),
		.id_funct3_i(id_funct3_o),
		.id_funct7_i(id_funct7_o),
		.ex_mem_i_inst_auipc_i(mem_i_inst_auipc),
		.irq_i(irq_i),
		.trap_flush_id_ex_req_i(trap_flush_id_ex_req),
        .div_stall_req_i(div_stall_req_o),
		.ex_mem_req_stall_i(ex_mem_req_stall_o),
		.trap_entry_i(ctrl_trap_entry_i),
		.ex_pc_target_i(ex_pc_target_o),
		.ex_mem_regwrite_en_i(mem_regwrite_en_i),
		.mem_wb_regwrite_en_i(wb_regwrite_en_o),
		.id_ex_rs1_addr_i(ex_rs1_addr_i),
		.id_ex_rs2_addr_i(ex_rs2_addr_i),
		.id_ex_mux_result_src_i(ex_mux_result_src_i),
		.ex_mux_pcsrc_i(ex_mux_pcsrc_o),
		.if_id_rs1_addr_i(reg_rs1_addr),
		.if_id_rs2_addr_i(reg_rs2_addr),
		.id_ex_rd_addr_i(ex_regwrite_addr_i),
		.ex_mem_rd_addr_i(mem_regwrite_addr_i),
		.mem_wb_rd_addr_i(wb_regwrite_addr_o),
		.icache_load_stall_req_i(icache_load_stall_req),
		.dcache_load_stall_req_i(dcache_load_stall_req),
		.i_inst_auipc_o(id_i_inst_auipc_i),
		.regwrite_en_o(id_regwrite_en_i),
		.mux_alu_src1_o(id_mux_alu_src1_i),
		.mux_alu_src2_o(id_mux_alu_src2_i),
		.mux_result_src_o(id_mux_result_src_i),
		.mem_req_o(id_mem_req_i),
		.mem_we_o(id_mem_we_i),
		.mux_jump_o(id_mux_jump_i),
		.mux_branch_o(id_mux_branch_i),
		.mux_alu_ctrl_o(id_mux_alu_ctrl_i),
        .mux_mul_ctrl_o(id_mux_mul_ctrl_i),
		.mux_pctarget_src_o(id_mux_pctarget_src_i),
		.mux_loadtype_o(id_mux_loadtype_i),
		.mux_storetype_o(id_mux_storetype_i),
		.mux_imm_src_o(id_mux_imm_src_i),
		.w_suffix_o(id_w_suffix_o),
		.mux_pcsrc_o(ctrl_mux_pcsrc),
		.jump_target_o(ctrl_pc_target),
		.mux_forward_rs1_o(ex_mux_forward_rs1_i),
		.mux_forward_rs2_o(ex_mux_forward_rs2_i),
		.irq_o(mem_irq_i),
		.stall_if_req_o(stall_if_req),
		.stall_id_req_o(stall_id_req),
        .stall_ex_req_o(stall_ex_req),
		.stall_mem_req_o(stall_mem_req),
		.flush_id_req_o(flush_id_req),
		.flush_ex_req_o(flush_ex_req),
		.flush_mem_req_o(flush_mem_req)
	);

	csr_reg i_csr_reg(
		.clk(clk),
		.rst_n(rst_n),
		.wr_en_i(mem_csr_wr_en_o),
		.wr_addr_i(mem_csr_wr_addr_o),
		.wr_data_i(mem_csr_wr_data_o),
		.rd_addr_i(mem_csr_rd_addr_o),
		.rd_data_o(mem_csr_rd_data_i),
		.csr_mie_o(mem_csr_mie_i),
		.csr_mtvec_o(mem_csr_mtvec_i),
		.csr_mepc_o(mem_csr_mepc_i),
		.csr_mstatus_o(mem_csr_mstatus_i)
	);

	trap i_trap(
		.clk(clk),
		.rst_n(rst_n),
		.pc_i(trap_pc_i),
		.csr_mtvec_i(mem_csr_mtvec_o),
		.csr_mepc_i(mem_csr_mepc_o),
		.csr_mstatus_i(mem_csr_mstatus_o),
		.mie_i(mem_csr_mie_o),
		.trap_code_i(mem_trap_code_o),
		.csr_we_o(mem_csr_wr_en_i),
		.csr_wr_addr_o(mem_csr_wr_addr_i),
		.csr_wr_data_o(mem_csr_wr_data_i),
		.trap_entry_o(mem_trap_entry_i),
		.trap_assert_o(trap_assert),
		.flush_id_ex_req_o(trap_flush_id_ex_req)
	);

endmodule
